/**
 * @file   Actions.java
 * @author Enrique Madrid <e.madrid@lpcsite.com>
 * @date   Tue Aug  7 11:23:27 2007
 *
 * @brief  Administrador de acciones.
 *
 *
 */

package sim.framework;

import java.util.*;

public final class Actions {

    private static final int QUEUE_INIT_SIZE = 4;

    private static final int LOCK_FOR_APPEND = 1;
    private static final int LOCK_FOR_REMOVE = 2;
    private static final int LOCK_FOR_DELETE = 3;
    
    private Simlet m_Simlet;

    private Vector m_Pending;
    private Vector m_Recycle;
    
    /**
     *  Contructor.
     *
     * @param s Referencia a un objeto Simlet.
     *
     * @return Devuelve una referencia a un objeto del tipo Actions.
     */
    public Actions(Simlet s) {
        m_Simlet = s;
        m_Pending = new Vector(QUEUE_INIT_SIZE);
        m_Recycle = new Vector(QUEUE_INIT_SIZE);
    }
    
    private synchronized Module lock(int lockFor, Module back, Module next, int route) {
	Module module = null;
        switch (lockFor) {
	case LOCK_FOR_APPEND:
	    lockedForAppend(back, next);
	    break;
	case LOCK_FOR_REMOVE:
	    module = lockedForRemove(route);
	    break;
	case LOCK_FOR_DELETE:
	    lockedForDelete();
	    break;
        }
	return module;
    }
    
    private Action newAction(Module back, Module next) {
        Action action = null;
        if (m_Recycle.size() > 0) {
            action = (Action)m_Recycle.firstElement();
            m_Recycle.removeElement(action);
            action.m_ModBack = back;
            action.m_ModNext = next;
        }
	else {
	    action = new Action(back, next);
	}
	return action;
    }
    
    private void lockedForAppend(Module back, Module next) {
        Action action = newAction(back, next);
        m_Pending.addElement(action);
    }
        
    private Module lockedForRemove(int route) {
        Action action;
        Module module;
        

	module = null;
	if (m_Pending.size() > 0) {
	    action = (Action)m_Pending.lastElement();
	    m_Pending.removeElement(action);
	    m_Recycle.addElement(action);
	    switch(route) {
	    case Executable.STATE_BACK:
		module = action.m_ModBack;
		break;
	    case Executable.STATE_NEXT:
		module = action.m_ModNext;
	    }
	}
	
	return module;
    }
    
    private void lockedForDelete() {
	// Aqui se deberia mandar todos a m_Recycle.
	// por ahora ...
        m_Pending.removeAllElements();
    }
    
    /**
     *  Registra una accion a tomar en caso de éxito o fracaso.
     *
     * Una accion esta compuesta de una cupla de módulos; uno módulo es
     * es registrado para ser ejecutado en caso de éxito, y el otro es
     * registrado para ser ejecutado en caso de fracaso.
     *
     * Las acciones son registradas en una cola del tipo FIFO; es decir,
     * la primera opcion registrada es la primera acción despachada.
     *
     * @param back Módulo que se ejecutará en caso de fracaso.
     * @param next Módulo que se ejecutará en caso de éxito.
     * @see execBack()
     * @see execNext()
     */
    public void append(Module back, Module next) {
        lock(Actions.LOCK_FOR_APPEND, back, next, 0);
    }
    
    /**
     *  Ejecuta el módulo registrado para el caso fracaso.
     *
     * Esta función extrae de la cola la accion de turno, y ejecuta
     * el módulo en registrado para en caso de fracaso en estado
     * Executable.STATE_BACK.
     *
     * @see queue()
     * @see execNext()
     */
    public Module remove(int route) {
        return lock(Actions.LOCK_FOR_REMOVE, null, null, route);
    }
    
    /**
     *  Borra toda la cola de acciones registradas.
     *
     * Esta función es utilizada por el framework para limpiar la cola de
     * módulos programados puesto que algo prioritario ha sucedido.
     * Por ejemplo, si hay un error de entrada/salida y el framework debe
     * restablecer estados, liberar recursos, y notificar al usuario; el
     * framework llama a esta función y ejecuta un módulo que se encarga
     * de todo lo anterior.
     *
     */
    public void delete() {
        lock(Actions.LOCK_FOR_DELETE, null, null, 0);
    }         
}
